/****************************************************************************
**  Tite Interactive Text Engine (TiTE)
**  Copyright (C) 2010  Eisoft Group
**
**  This file is part of TiTE.
**
**  TiTE is free software: you can redistribute it and/or modify
**  it under the terms of the GNU General Public License as published by
**  the Free Software Foundation, either version 3 of the License, or
**  (at your option) any later version.
**
**  TiTE is distributed in the hope that it will be useful,
**  but WITHOUT ANY WARRANTY; without even the implied warranty of
**  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
**  GNU General Public License for more details.
**
**  You should have received a copy of the GNU General Public License
**  along with TiTE.  If not, see <http://www.gnu.org/licenses/>.
****************************************************************************/

/*!
 * \file SingletonLifetimeManager_.cpp
 *
 * \date 01/10/2011
 */

#include <algorithm>
#include <cstdlib>

#include <tite/core/safe_delete.hpp>
#include <tite/core/singleton/detail/SingletonLifetimeManager_.hpp>
#include <tite/core/singleton/singleton.hpp>

/*!
 * \namespace tite
 *
 * \brief The TiTE namespace.
 */
namespace tite
{
    /*!
     * \namespace core
     *
     * \brief The TiTE core namespace.
     */
    namespace core
    {
///! Surpress MSVC warning for default-initialized arrays; behavior is wanted.
#ifdef _MSC_VER
#   pragma warning(disable: 4351)
#endif /* _MSC_VER */

        /*!
         * \brief SingletonLifetimeManager_ ctor.
         */
        SingletonLifetimeManager_::SingletonLifetimeManager_(void)
            : m_pSingletonLifetimes()
        {
        }

#ifdef _MSC_VER
#   pragma warning(default: 4351)
#endif /* _MSC_VER */

        /*! 
         * \brief SingletonLifetimeManager_ dtor.
         */
        SingletonLifetimeManager_::~SingletonLifetimeManager_(void)
        {
            for (priority_levels::PriorityLevel i = priority_levels::High; i >= priority_levels::Low; i = priority_levels::PriorityLevel(i - 1))
            {
                if (m_pSingletonLifetimes[i])
                {
                    for (stdext::vector<func_t *>::iterator it = m_pSingletonLifetimes[i]->begin(); it != m_pSingletonLifetimes[i]->end(); ++it)
                    {
                        (**it)();
                        safe_delete(&(*it));
                    }

                    safe_delete(&m_pSingletonLifetimes[i]);
                }
            }
        }

        /*!
         * \brief Registers a function of pseudotype "void (void)" to perform the
         *        deletion of a singleton; the priority specifies when the corresponding
         *        deletion function will be invoked with respect to other managed
         *        singletons.
         *
         * \param deleter   Deletion function.
         * \param priority  Destruction priority for the associated singleton.
         *
         * \return Pointer to the registered function; likely to be used for
         *         unregistration.
         */
        SingletonLifetimeManager_::func_t *const SingletonLifetimeManager_::registerDeleter(const func_t & deleter, priority_levels::PriorityLevel priority)
        {
            if (!m_pSingletonLifetimes[priority])
                m_pSingletonLifetimes[priority] = new stdext::vector<func_t *>;

            m_pSingletonLifetimes[priority]->push_back(new func_t(deleter));
            return m_pSingletonLifetimes[priority]->back();
        }

        /*!
         * \brief Unregisters the specified deletion function to prevent invocation
         *        at application shutdown, thus the singleton must be destroyed manually.
         *
         * \param deleterFnPtr  Deletion function to unregister.
         */
        void SingletonLifetimeManager_::unregisterDeleter(func_t *const deleterFnPtr)
        {
            for (size_t i = 0; i < priority_levels::PriorityLevelCount; i++)
                m_pSingletonLifetimes[i]->erase(stdext::remove(m_pSingletonLifetimes[i]->begin(), 
                                                            m_pSingletonLifetimes[i]->end(), 
                                                            deleterFnPtr),
                                                m_pSingletonLifetimes[i]->end());
        }
    }// End of core namespace
}// End of tite namespace